package com.bigflexlib.x.flash.display
{



	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.geom.Point;
	


	public class DisplayObjectUtil
	{
		



		/**
		 * 
		 * Will modify scaleX, scaleY, x and y only one time to apply the desired zoomFactor ( scaleX *= scaleFactor ).
		 * x and y are modified in such a way that the display object doesn't move.
		 * Anchor is specified IN PARENT COORDINATE SPACE.
		 * 
		 * Numbers are used instead of a Point object to avoid creating unnecessary Point instances.
		 * 
		 * 
		 * @param o
		 * @param zoomFactor
		 * @param anchorX
		 * @param anchorY
		 * 
		 */
		public static function applyAtomicZoom( o:DisplayObject, zoomFactor:Number, anchorX:Number, anchorY:Number ):void
		{
			o.x = anchorX - ( anchorX - o.x ) * zoomFactor;
			o.y = anchorY - ( anchorY - o.y ) * zoomFactor;								
			o.scaleX *= zoomFactor;
			o.scaleY *= zoomFactor;			
		}
		
		
		

		/**
		 * 
		 * Similar as applyAtomicZoom(), but instead of applying the zoom to a display object
		 * returns the new location that a generic target should have after applying the zoom.
		 * 
		 * 
		 * @param zoomTargetX
		 * @param zoomTargetY
		 * @param zoomFactor
		 * @param anchorX
		 * @param anchorY
		 * @return 
		 * 
		 */		 		
		public static function getAtomicZoomPostLocation( zoomTargetX:Number, zoomTargetY:Number, zoomFactor:Number, anchorX:Number, anchorY:Number ):Point
		{
			return new Point( anchorX - ( anchorX - zoomTargetX ) * zoomFactor, anchorY - ( anchorY - zoomTargetY ) * zoomFactor );	
		}
		
		



		public static function getFirstCommonAncestor( o1:DisplayObject, o2:DisplayObject ):DisplayObjectContainer
		{
			// TODO: optimize
			var a1:Array = getAncestors( o1 );
			var a2:Array = getAncestors( o2 );
			for each ( var a:* in a1 )
				if ( a2.indexOf( a ) != -1 )
					return a;
			return null;
		}

		
		
		/**
		 * 
		 * Returns all ancestors in parent, grandparent, etc order.
		 * 
		 * @param o
		 * @return 
		 * 
		 */		
		public static function getAncestors( o:DisplayObject ):Array
		{
			var arr:Array = [ ];
			while ( o.parent != null )
			{
				o = o.parent;
				arr.push( o );		
			}
			return arr;
		}
		
		


		/**
		 * 
		 * 
		 * @param o
		 * @param ancestor
		 * @param included
		 * @return 
		 * 
		 * WARNING: may return NULL if ancestor is NOT found
		 * 
		 */		
		public static function getAncestorsUpTo( o:DisplayObject, ancestor:DisplayObjectContainer, included:Boolean=true ):Array
		{
		
			var arr:Array = [ ];
			while ( o.parent != null )
			{

				o = o.parent;
				
				if ( o == ancestor )
				{

					if ( included )
						arr.push( o );
					
					return arr;			

				}

				arr.push( o );		
			}
			
			return null;		
		
		}
		

	}

}
